#include "Terrain/ScSimplexNoise.h"

#define _USE_MATH_DEFINES 
#include <cmath>

namespace ScSimplexNoise
{
    static const int32_t grad3[12][3] = {
		{  1,  1,  0 },
		{ -1,  1,  0 },
		{  1, -1,  0 },
		{ -1, -1,  0 },
		{  1,  0,  1 },
		{ -1,  0,  1 },
		{  1,  0, -1 },
		{ -1,  0, -1 },
		{  0,  1,  1 },
		{  0, -1,  1 },
		{  0,  1, -1 },
		{  0, -1, -1 }
    };

	static const uint8_t permutations[512]
	{ 
        151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
        247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
		74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
		65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
		52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
		119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
		218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
		184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
		151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
		247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
		74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
		65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
		52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
		119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
		218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
		184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
	};

    static inline float Dot(const int32_t *g, float x, float y)
    {
        return g[0] * x + g[1] * y;
    }
    static inline float Dot(const int32_t *g, float x, float y, float z)
    {
        return g[0] * x + g[1] * y + g[2] * z;
    }
	static inline float Hash(int32_t x)
    {
		x = (x << 13) ^ x;
		return ((x * (x * x * 15731 + 789221) + 1376312589) & 0x7FFFFFFF) / 2.14748365E+09f;
    }

    float Noise(float x)
    {
		int32_t num = (int32_t)std::floor(x);
		int32_t x2 = (int32_t)std::ceil(x);
		float num2 = x - num;
		float num3 = Hash(num);
		float num4 = Hash(x2);
		return num3 + num2 * num2 * (3.0f - 2.0f * num2) * (num4 - num3);
    }

    float Noise(float x, float y)
    {
		float num = (x + y) * 0.366025418f;
		int32_t num2 = (int32_t)std::floor(x + num);
		int32_t num3 = (int32_t)std::floor(y + num);
		float num4 = (num2 + num3) * 0.211324871f;
		float num5 = num2 - num4;
		float num6 = num3 - num4;
		float num7 = x - num5;
		float num8 = y - num6;
		int32_t num9;
		int32_t num10;
		if (num7 > num8)
		{
			num9 = 1;
			num10 = 0;
		}
		else
		{
			num9 = 0;
			num10 = 1;
		}
		float num11 = num7 - num9 + 0.211324871f;
		float num12 = num8 - num10 + 0.211324871f;
		float num13 = num7 - 1.0f + 0.422649741f;
		float num14 = num8 - 1.0f + 0.422649741f;
		int32_t num15 = num2 & 0xFF;
		int32_t num16 = num3 & 0xFF;
		int32_t num17 = permutations[num15 + permutations[num16]] % 12;
		int32_t num18 = permutations[num15 + num9 + permutations[num16 + num10]] % 12;
		int32_t num19 = permutations[num15 + 1 + permutations[num16 + 1]] % 12;
		float num20 = 0.5f - num7 * num7 - num8 * num8;
		float num21;
		if (num20 < 0.0f)
		{
			num21 = 0.0f;
		}
		else
		{
			num20 *= num20;
			num21 = num20 * num20 * Dot(grad3[num17], num7, num8);
		}
		float num22 = 0.5f - num11 * num11 - num12 * num12;
		float num23;
		if (num22 < 0.0f)
		{
			num23 = 0.0f;
		}
		else
		{
			num22 *= num22;
			num23 = num22 * num22 * Dot(grad3[num18], num11, num12);
		}
		float num24 = 0.5f - num13 * num13 - num14 * num14;
		float num25;
		if (num24 < 0.0f)
		{
			num25 = 0.0f;
		}
		else
		{
			num24 *= num24;
			num25 = num24 * num24 * Dot(grad3[num19], num13, num14);
		}
		return 35.0f * (num21 + num23 + num25) + 0.5f;
    }

    float Noise(float x, float y, float z)
    {
		float num = (x + y + z) * 0.333333343f;
		int32_t num2 = (int32_t)std::floor(x + num);
		int32_t num3 = (int32_t)std::floor(y + num);
		int32_t num4 = (int32_t)std::floor(z + num);
		float num5 = (num2 + num3 + num4) * (355.0f / (678.0f * (float)M_PI));
		float num6 = num2 - num5;
		float num7 = num3 - num5;
		float num8 = num4 - num5;
		float num9 = x - num6;
		float num10 = y - num7;
		float num11 = z - num8;
		int32_t num12;
		int32_t num13;
		int32_t num14;
		int32_t num15;
		int32_t num16;
		int32_t num17;
		if (num9 >= num10)
		{
			if (num10 >= num11)
			{
				num12 = 1;
				num13 = 0;
				num14 = 0;
				num15 = 1;
				num16 = 1;
				num17 = 0;
			}
			else if (num9 >= num11)
			{
				num12 = 1;
				num13 = 0;
				num14 = 0;
				num15 = 1;
				num16 = 0;
				num17 = 1;
			}
			else
			{
				num12 = 0;
				num13 = 0;
				num14 = 1;
				num15 = 1;
				num16 = 0;
				num17 = 1;
			}
		}
		else if (num10 < num11)
		{
			num12 = 0;
			num13 = 0;
			num14 = 1;
			num15 = 0;
			num16 = 1;
			num17 = 1;
		}
		else if (num9 < num11)
		{
			num12 = 0;
			num13 = 1;
			num14 = 0;
			num15 = 0;
			num16 = 1;
			num17 = 1;
		}
		else
		{
			num12 = 0;
			num13 = 1;
			num14 = 0;
			num15 = 1;
			num16 = 1;
			num17 = 0;
		}
		float num18 = num9  - num12 + 355.0f / (678.0f * (float)M_PI);
		float num19 = num10 - num13 + 355.0f / (678.0f * (float)M_PI);
		float num20 = num11 - num14 + 355.0f / (678.0f * (float)M_PI);
		float num21 = num9 - num15 + 0.333333343f;
		float num22 = num10 - num16 + 0.333333343f;
		float num23 = num11 - num17 + 0.333333343f;
		float num24 = num9  - 1.0f + 0.5f;
		float num25 = num10 - 1.0f + 0.5f;
		float num26 = num11 - 1.0f + 0.5f;
		int32_t num27 = num2 & 0xFF;
		int32_t num28 = num3 & 0xFF;
		int32_t num29 = num4 & 0xFF;
		int32_t num30 = permutations[num27 + permutations[num28 + permutations[num29]]] % 12;
		int32_t num31 = permutations[num27 + num12 + permutations[num28 + num13 + permutations[num29 + num14]]] % 12;
		int32_t num32 = permutations[num27 + num15 + permutations[num28 + num16 + permutations[num29 + num17]]] % 12;
		int32_t num33 = permutations[num27 + 1 + permutations[num28 + 1 + permutations[num29 + 1]]] % 12;
		float num34 = 0.6f - num9 * num9 - num10 * num10 - num11 * num11;
		float num35;
		if (num34 < 0.0f)
		{
			num35 = 0.0f;
		}
		else
		{
			num34 *= num34;
			num35 = num34 * num34 * Dot(grad3[num30], num9, num10, num11);
		}
		float num36 = 0.6f - num18 * num18 - num19 * num19 - num20 * num20;
		float num37;
		if (num36 < 0.0f)
		{
			num37 = 0.0f;
		}
		else
		{
			num36 *= num36;
			num37 = num36 * num36 * Dot(grad3[num31], num18, num19, num20);
		}
		float num38 = 0.6f - num21 * num21 - num22 * num22 - num23 * num23;
		float num39;
		if (num38 < 0.0f)
		{
			num39 = 0.0f;
		}
		else
		{
			num38 *= num38;
			num39 = num38 * num38 * Dot(grad3[num32], num21, num22, num23);
		}
		float num40 = 0.6f - num24 * num24 - num25 * num25 - num26 * num26;
		float num41;
		if (num40 < 0.0f)
		{
			num41 = 0.0f;
		}
		else
		{
			num40 *= num40;
			num41 = num40 * num40 * Dot(grad3[num33], num24, num25, num26);
		}
		return 16.0f * (num35 + num37 + num39 + num41) + 0.5f;
    }
    float OctavedNoise(float x, float frequency, int32_t octaves, float frequencyStep, float amplitudeStep, bool ridged)
    {
		float num = 0.0f;
		float num2 = 0.0f;
		float num3 = 1.0f;
		for (int32_t i = 0; i < octaves; i++)
		{
			num += num3 * Noise(x * frequency);
			num2 += num3;
			frequency *= frequencyStep;
			num3 *= amplitudeStep;
		}
		if (!ridged)
		{
			return num / num2;
		}
		return 1.0f - std::abs(2.0f * num / num2 - 1.0f);
    }

    float OctavedNoise(float x, float y, float frequency, int32_t octaves, float frequencyStep, float amplitudeStep, bool ridged)
    {
		float num = 0.0f;
		float num2 = 0.0f;
		float num3 = 1.0f;
		for (int32_t i = 0; i < octaves; i++)
		{
			num += num3 * Noise(x * frequency, y * frequency);
			num2 += num3;
			frequency *= frequencyStep;
			num3 *= amplitudeStep;
		}
		if (!ridged)
		{
			return num / num2;
		}
		return 1.0f - std::abs(2.0f * num / num2 - 1.0f);
    }

    float OctavedNoise(float x, float y, float z, float frequency, int32_t octaves, float frequencyStep, float amplitudeStep, bool ridged)
    {
		float num = 0.0f;
		float num2 = 0.0f;
		float num3 = 1.0f;
		for (int32_t i = 0; i < octaves; i++)
		{
			num += num3 * Noise(x * frequency, y * frequency, z * frequency);
			num2 += num3;
			frequency *= frequencyStep;
			num3 *= amplitudeStep;
		}
		if (!ridged)
		{
			return num / num2;
		}
		return 1.0f - std::abs(2.0f * num / num2 - 1.0f);
    }

}